/**
* 版权所有:版权所有(C) 2020，卓信科技
* 系统名称:FOL2020-财务在线
* 文件名称:StringUtil.java
* 模块名称:StringUtil
* 创建日期:2020年5月19日
* 作        者:Baisong
* 内容摘要:字符串处理工具类
*/
package com.zx.emanage.util.gen;


import java.io.UnsupportedEncodingException;

/**
 * 类  名  称:StringUtil
 *
 * 内容摘要:字符串处理工具类
 *
 * 作        者:Baisong
 */
public class StringUtil
{

	// ---------------------------------------------------------------- replace

	/**
	 * 用字符串with替换所有的字符串s中的字符串sub。
	 * 
	 * @param s
	 *            需要处理的字符串
	 * @param sub
	 *            需要替换的字符串
	 * @param with
	 *            用来替换的字符串
	 */
	public static String replace(String s, String sub, String with)
	{
		int c = 0;
		int i = s.indexOf(sub, c);
		// 判断
		if (i == -1)
		{
			return s;
		}
		int length = s.length();
		StringBuilder sb = new StringBuilder(length + with.length());
		do
		{
			sb.append(s.substring(c, i));
			sb.append(with);
			c = i + sub.length();
		} while ((i = s.indexOf(sub, c)) != -1);
		// 判断
		if (c < length)
		{
			sb.append(s.substring(c, length));
		}
		return sb.toString();
	}

	/**
	 * 替换字符串中的所有字符为另外一个with字符
	 * 
	 * @param s
	 *            需要处理的字符串
	 * @param sub
	 *            需要替换的字符
	 * @param with
	 *            使用的替换字符
	 */
	public static String replaceChar(String s, char sub, char with)
	{
		int startIndex = s.indexOf(sub);
		// 判断
		if (startIndex == -1)
		{
			return s;
		}
		char[] str = s.toCharArray();
		// 循环
		for (int i = startIndex; i < str.length; i++)
		{
			// 判断
			if (str[i] == sub)
			{
				str[i] = with;
			}
		}
		return new String(str);
	}

	/**
	 * 将字符串中所有字符数组sub一样的，用字符数组with替换
	 * 
	 * @param s
	 *            需要处理的字符串
	 * @param sub
	 *            需要替换的字符数组
	 * @param with
	 *            用来替换的字符数组
	 */
	public static String replaceChars(String s, char[] sub, char[] with)
	{
		char[] str = s.toCharArray();
		// 循环
		for (int i = 0; i < str.length; i++)
		{
			char c = str[i];
			// 循环
			for (int j = 0; j < sub.length; j++)
			{
				// 判断
				if (c == sub[j])
				{
					str[i] = with[j];
					break;
				}
			}
		}
		return new String(str);
	}

	/**
	 * 用替换字符串替换原字符串中第一次出现的子串
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            需要替换的子串
	 * @param with
	 *            替代的子串
	 */
	public static String replaceFirst(String s, String sub, String with)
	{
		int i = s.indexOf(sub);
		// 判断
		if (i == -1)
		{
			return s;
		}
		return s.substring(0, i) + with + s.substring(i + sub.length());
	}

	/**
	 * 用另外一个字符替换字符串中的第一次出现的给定字符。
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            需要替换的字符
	 * @param with
	 *            替换的字符
	 */
	public static String replaceFirst(String s, char sub, char with)
	{
		int index = s.indexOf(sub);
		// 判断
		if (index == -1)
		{
			return s;
		}
		char[] str = s.toCharArray();
		str[index] = with;
		return new String(str);
	}

	/**
	 * 用另外的字符串提供源字符串中最后出现的给定子串
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            需要替换的子字符串
	 * @param with
	 *            替代的子字符串
	 */
	public static String replaceLast(String s, String sub, String with)
	{
		int i = s.lastIndexOf(sub);
		// 判断
		if (i == -1)
		{
			return s;
		}
		return s.substring(0, i) + with + s.substring(i + sub.length());
	}

	/**
	 * 用给定字符替换字符串中最后一次出现的给定字符。
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            需要替换的字符
	 * @param with
	 *            替换字符
	 */
	public static String replaceLast(String s, char sub, char with)
	{
		int index = s.lastIndexOf(sub);
		// 判断
		if (index == -1)
		{
			return s;
		}
		char[] str = s.toCharArray();
		str[index] = with;
		return new String(str);
	}

	// ---------------------------------------------------------------- remove

	/**
	 * 删除字符串中含有的给定子串
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            需要删除掉的子字符串
	 */
	public static String remove(String s, String sub)
	{
		int c = 0;
		int sublen = sub.length();
		// 判断
		if (sublen == 0)
		{
			return s;
		}
		int i = s.indexOf(sub, c);
		// 判断
		if (i == -1)
		{
			return s;
		}
		StringBuilder sb = new StringBuilder(s.length());
		do
		{
			sb.append(s.substring(c, i));
			c = i + sublen;
		} 
		while ((i = s.indexOf(sub, c)) != -1);
		// 判断
		if (c < s.length())
		{
			sb.append(s.substring(c, s.length()));
		}
		return sb.toString();
	}

	/**
	 * 将字符串中与给定字符相同的所有字符删除掉
	 * 
	 * @param src
	 *            源字符串
	 * @param chars
	 *            含有需要删除字符的字符串
	 */
	public static String removeChars(String src, String chars)
	{
		int i = src.length();
		StringBuilder sb = new StringBuilder(i);
		// 判断
		for (int j = 0; j < i; j++)
		{
			char c = src.charAt(j);
			// 判断
			if (chars.indexOf(c) == -1)
			{
				sb.append(c);
			}
		}
		return sb.toString();
	}

	/**
	 * 从字符串中删除给定的字符
	 * 
	 * @param src
	 *            源字符串
	 * @param chars
	 *            需要删除的字符
	 */
	public static String removeChars(String src, char... chars)
	{
		int i = src.length();
		StringBuilder sb = new StringBuilder(i);
		mainloop: for (int j = 0; j < i; j++)
		{
			char c = src.charAt(j);
			// 判断
			for (char aChar : chars)
			{
				// 判断
				if (c == aChar)
				{
					continue mainloop;
				}
			}
			sb.append(c);
		}
		return sb.toString();
	}

	/**
	 * 从字符串中删除所有与给定相同的字符
	 * 
	 * @param string
	 *            源字符串
	 * @param ch
	 *            需要删除的字符
	 */
	public static String remove(String string, char ch)
	{
		int stringLen = string.length();
		char[] result = new char[stringLen];
		int offset = 0;
		// 循环
		for (int i = 0; i < stringLen; i++)
		{
			char c = string.charAt(i);
			// 判断
			if (c == ch)
			{
				continue;
			}

			result[offset] = c;
			offset++;
		}

		return new String(result, 0, offset);
	}


	/**
	 * 判断一个字符串是否为空（<code>null</code>或者空串）
	 */
	public static boolean isEmpty(String string)
	{
		return ((string == null) || (string.length() == 0));
	}

	/**
	 * 判断多个字符串中是否有空串
	 * 
	 * @see #isEmpty(String)
	 */
	public static boolean isAllEmpty(String... strings)
	{
		// 循环
		for (String string : strings)
		{
			// 判断
			if (isEmpty(string) == false)
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断一个字符串是否是blank(<code>null</code>或者
	 * {@link #containsOnlyWhitespaces(String)}空格)
	 */
	public static boolean isBlank(String string)
	{
		return ((string == null) || containsOnlyWhitespaces(string));
	}

	/**
	 * 判断一个字符串是否是不blank空（<code>null</code>或者空格）
	 */
	public static boolean isNotBlank(String string)
	{
		return ((string != null) && !containsOnlyWhitespaces(string));
	}

	/**
	 * 判断多个字符串中是否含有blank字符串
	 */
	public static boolean isAllBlank(String... strings)
	{
		// 循环
		for (String string : strings)
		{
			// 判断
			if (isBlank(string) == false)
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断字符串是否就只含有空格。如果是返回<code>true</code>
	 */
	public static boolean containsOnlyWhitespaces(String string) 
	{
		int size = string.length();
		//循环
		for (int i = 0; i < size; i++) 
		{
			char c = string.charAt(i);
			// 判断
			if (CharUtil.isWhitespace(c) == false) 
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断字符串是否只含有数字，如果是返回<code>true</code>
	 */
	public static boolean containsOnlyDigits(String string)
	{
		int size = string.length();
		//// 判断
		for (int i = 0; i < size; i++)
		{
			char c = string.charAt(i);
			// 判断
			if (CharUtil.isDigit(c) == false)
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断是一个字符串是否非空
	 */
	public static boolean isNotEmpty(String string)
	{
		return string != null && string.length() > 0;
	}

	// ----------------------------------------------------------------
	// capitalize

	/**
	 * 将字符串首字母变大写，其他字符不变
	 * 
	 * @param str
	 *            需要首字母大写的字符串
	 * @see #uncapitalize(String)
	 */
	public static String capitalize(String str)
	{
		return changeFirstCharacterCase(true, str);
	}

	/**
	 * 将字符串<code>String</code>首字母小写，其他字母不变。
	 * 
	 * @param str
	 *            首字母需要小写的字符串
	 * @return 首字母小写的字符串，如果<code>null</code>返回<code>null</code>
	 * @see #capitalize(String)
	 */
	public static String uncapitalize(String str)
	{
		return changeFirstCharacterCase(false, str);
	}

	/**
	 * Internal method for changing the first character case. It is
	 * significantly faster using StringBuffers then just simply Strings.
	 */
	private static String changeFirstCharacterCase(boolean capitalize,
			String string)
	{
		int strLen = string.length();
		// 判断
		if (strLen == 0)
		{
			return string;
		}

		char ch = string.charAt(0);
		char modifiedCh;
		// 判断
		if (capitalize)
		{
			modifiedCh = Character.toUpperCase(ch);
		} 
		else
		{
			modifiedCh = Character.toLowerCase(ch);
		}
		// 判断
		if (modifiedCh == ch)
		{
			// no change, return unchanged string
			return string;

		}

		StringBuilder builder = new StringBuilder(strLen);
		builder.append(modifiedCh);
		builder.append(string.substring(1));
		return builder.toString();
	}

	/**
	 * 将字符串转换为Title风格的字符串
	 */
	public static String title(String string)
	{
		char[] chars = string.toCharArray();

		boolean wasWhitespace = true;
		//循环
		for (int i = 0; i < chars.length; i++)
		{
			char c = chars[i];
			// 判断
			if (CharUtil.isWhitespace(c))
			{
				wasWhitespace = true;
			} 
			else
			{
				// 判断
				if (wasWhitespace)
				{
					chars[i] = Character.toUpperCase(c);
				} 
				else
				{
					chars[i] = Character.toLowerCase(c);
				}
				wasWhitespace = false;
			}
		}

		return new String(chars);
	}

	// ---------------------------------------------------------------- truncate

	/**
	 * 字符串截断。将字符串按给定长度截断。
	 * 
	 * @param String string，需要截断的字符串
	 * @param int length，字符串截断的长度
	 * @return 按长度返回截断的字符串
	 */
	public static String truncate(String string, int length)
	{
		// 判断
		if (string.length() > length)
		{
			string = string.substring(0, length);
		}
		return string;
	}

	// ---------------------------------------------------------------- split

	/**
	 * 将字符通过tokens串拆分为几个部分。相当于正则表达式<code>String.split()</code>拆分方法。但是要比正则拆分方法快很多。<br />
	 * 
	 * Splits a string in several parts (tokens) that are separated by
	 * delimiter. Delimiter is <b>always</b> surrounded by two strings! If there
	 * is no content between two delimiters, empty string will be returned for
	 * that token. Therefore, the length of the returned array will always be:
	 * #delimiters + 1.
	 * <p>
	 * Method is much, much faster then regexp <code>String.split()</code>, and
	 * a bit faster then <code>StringTokenizer</code>.
	 * 
	 * @param src
	 *            需要拆分的字符串
	 * @param delimiter
	 *            拆分的界定符
	 * 
	 * @return 拆分后的字符串数组
	 */
	public static String[] split(String src, String delimiter)
	{
		int maxparts = (src.length() / delimiter.length()) + 2;
		// one more for
		// the last
		int[] positions = new int[maxparts];
		int dellen = delimiter.length();

		int i, j = 0;
		int count = 0;
		positions[0] = -dellen;
		// 循环
		while ((i = src.indexOf(delimiter, j)) != -1)
		{
			count++;
			positions[count] = i;
			j = i + dellen;
		}
		count++;
		positions[count] = src.length();

		String[] result = new String[count];
		// 判断
		for (i = 0; i < count; i++)
		{
			result[i] = src.substring(positions[i] + dellen, positions[i + 1]);
		}
		return result;
	}

	/**
	 * 将字符串按照界定符（tokens）拆分为多个部分。界定符可以含有多个字符并且疆场被两个字符串包含。<br />
	 * Splits a string in several parts (tokens) that are separated by delimiter
	 * characters. Delimiter may contains any number of character and it is
	 * always surrounded by two strings.
	 * 
	 * @param src
	 *            需要拆分的字符串
	 * @param d
	 *            含有界定符的字符串
	 * 
	 * @return 拆分成多个字符串的数组
	 */
	public static String[] splitc(String src, String d)
	{
		// 判断
		if ((d.length() == 0) || (src.length() == 0))
		{
			return new String[] { src };
		}
		char[] delimiters = d.toCharArray();
		char[] srcc = src.toCharArray();

		int maxparts = srcc.length + 1;
		int[] start = new int[maxparts];
		int[] end = new int[maxparts];

		int count = 0;

		start[0] = 0;
		int s = 0, e;
		// 判断
		if (CharUtil.equalsOne(srcc[0], delimiters) == true)
		{
			// string starts with delimiter
			end[0] = 0;
			count++;
			s = CharUtil.findFirstDiff(srcc, 1, delimiters);
			// 判断
			if (s == -1)
			{
				// nothing after delimiters
				return new String[] { "", "" };
			}
			start[1] = s;
			// new start
		}
		while (true)
		{
			// find new end
			e = CharUtil.findFirstEqual(srcc, s, delimiters);
			// 判断
			if (e == -1)
			{
				end[count] = srcc.length;
				break;
			}
			end[count] = e;

			// find new start
			count++;
			s = CharUtil.findFirstDiff(srcc, e, delimiters);
			// 判断
			if (s == -1)
			{
				start[count] = end[count] = srcc.length;
				break;
			}
			start[count] = s;
		}
		count++;
		String[] result = new String[count];
		// 循环
		for (int i = 0; i < count; i++)
		{
			result[i] = src.substring(start[i], end[i]);
		}
		return result;
	}

	/**
	 * 按照给定的字符界定符（tokens），将字符串拆分为字符串数组
	 * 
	 * @param src
	 *            需要拆分的字符串
	 * @param delimiter
	 *            界定符字符串
	 * 
	 * @return 拆分后的字符串数组
	 */
	public static String[] splitc(String src, char delimiter)
	{
		// 判断
		if (src.length() == 0)
		{
			return new String[] { "" };
		}
		char[] srcc = src.toCharArray();

		int maxparts = srcc.length + 1;
		int[] start = new int[maxparts];
		int[] end = new int[maxparts];

		int count = 0;

		start[0] = 0;
		int s = 0, e;
		// 判断
		if (srcc[0] == delimiter)
		{
			// string starts with delimiter
			end[0] = 0;
			count++;
			s = CharUtil.findFirstDiff(srcc, 1, delimiter);
			// 判断
			if (s == -1)
			{
				// nothing after delimiters
				return new String[] { "", "" };
			}
			start[1] = s; 
			// new start
		}
		while (true)
		{
			// find new end
			e = CharUtil.findFirstEqual(srcc, s, delimiter);
			// 判断
			if (e == -1)
			{
				end[count] = srcc.length;
				break;
			}
			end[count] = e;

			// find new start
			count++;
			s = CharUtil.findFirstDiff(srcc, e, delimiter);
			// 判断
			if (s == -1)
			{
				start[count] = end[count] = srcc.length;
				break;
			}
			start[count] = s;
		}
		count++;
		String[] result = new String[count];
		// 循环
		for (int i = 0; i < count; i++)
		{
			result[i] = src.substring(start[i], end[i]);
		}
		return result;
	}

	/**
	 * 将字符串中出现的给定字符，压缩到只出现一次。（删除后续出现的字符）
	 * Compress multiple occurrences of given char into one appearance.
	 * 
	 * @param String s，需要处理的字符串
	 * @param char c，需要压缩保留一次的字符
	 * @return String 将字符串中出现的字符c只保留一次
	 */
	public static String compressChars(String s, char c)
	{
		int len = s.length();
		StringBuilder sb = new StringBuilder(len);
		boolean wasChar = false;
		// 判断
		for (int i = 0; i < len; i++)
		{
			char c1 = s.charAt(i);
			// 判断
			if (c1 == c)
			{
				// 判断
				if (wasChar)
				{
					continue;
				}
				wasChar = true;
			} 
			else
			{
				wasChar = false;
			}
			sb.append(c1);
		}
		// 判断
		if (sb.length() == len)
		{
			return s;
		}
		return sb.toString();
	}

	// ---------------------------------------------------------------- indexof
	// and ignore cases

	/**
	 * 从字符串中查找第一次出现子串的下标。搜索范围是[start,end)。相当于<code>String.indexOf(String, int)</code>
	 * 但是比String中的indexOf方法具有更好性能。
	 * 
	 * @param src
	 *            需要处理的字符串
	 * @param sub
	 *            需要查找的子串
	 * @param startIndex
	 *            查找的开始位置
	 * @param endIndex
	 *            查找的结束位置
	 * @return 返回子串第一次出现的下标，如果没有返回-1
	 */
	public static int indexOf(String src, String sub, int startIndex,
			int endIndex)
	{
		// 判断
		if (startIndex < 0)
		{
			startIndex = 0;
		}
		int srclen = src.length();
		// 判断
		if (endIndex > srclen)
		{
			endIndex = srclen;
		}
		int sublen = sub.length();
		// 判断
		if (sublen == 0)
		{
			return startIndex > srclen ? srclen : startIndex;
		}

		int total = endIndex - sublen + 1;
		char c = sub.charAt(0);
		// 循环
		mainloop: for (int i = startIndex; i < total; i++)
		{
			// 判断
			if (src.charAt(i) != c)
			{
				continue;
			}
			int j = 1;
			int k = i + 1;
			// 循环
			while (j < sublen)
			{
				// 判断
				if (sub.charAt(j) != src.charAt(k))
				{
					continue mainloop;
				}
				j++;
				k++;
			}
			return i;
		}
		return -1;
	}

	/**
	 * 从给定范围(startIndex,endIndex]内查找第一次出现的给定字符的下标。如果没有返回-1。
	 * 注意查找范围的开闭区间情况。
	 * 
	 * @param String src，需要处理的字符串
	 * @param char c，查找的字符
	 * @param int startIndex，开始查找的位置
	 * @param int endIndex，查找结束的位置
	 * @return int 查找某个字符在字符串中第一次出现的下标，没有返回-1
	 */
	public static int indexOf(String src, char c, int startIndex, int endIndex)
	{
		// 判断
		if (startIndex < 0)
		{
			startIndex = 0;
		}
		int srclen = src.length();
		// 判断
		if (endIndex > srclen)
		{
			endIndex = srclen;
		}
		// 循环
		for (int i = startIndex; i < endIndex; i++)
		{
			// 判断
			if (src.charAt(i) == c)
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 从给定范围(startIndex,endIndex]内查找第一次出现的给定字符的下标。<b>忽略大小写</b>。如果没有返回-1。
	 * 注意查找范围的开闭区间情况。
	 */
	public static int indexOfIgnoreCase(String src, char c, int startIndex,
			int endIndex)
	{
		// 判断
		if (startIndex < 0)
		{
			startIndex = 0;
		}
		int srclen = src.length();
		// 判断
		if (endIndex > srclen)
		{
			endIndex = srclen;
		}
		c = Character.toLowerCase(c);
		// 判断
		for (int i = startIndex; i < endIndex; i++)
		{
			// 判断
			if (Character.toLowerCase(src.charAt(i)) == c)
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 查找子串第一次在字符串中出现的下标，查找中<b>忽略大小写</b>。
	 * 
	 * @param src
	 *            需要处理的字符串
	 * @param subS
	 *            需要查找的子串
	 * 
	 * @return 返回子串在字符串第一次出现的下标，如果没有返回-1
	 * @see #indexOfIgnoreCase(String, String, int)
	 */
	public static int indexOfIgnoreCase(String src, String subS)
	{
		return indexOfIgnoreCase(src, subS, 0, src.length());
	}

	/**
	 * 从给定位置开始查找子串在源字符串中第一次出现的下标。查找中<b>忽略大小写</b>。
	 * 
	 * @param src
	 *            需要处理的源字符串
	 * @param subS
	 *            需要查找的子串
	 * @param startIndex
	 *            开始查找的下标
	 * 
	 * @return 子串在源字符串中从给定位置开始第一次出现的下标，如果没有返回-1
	 */
	public static int indexOfIgnoreCase(String src, String subS, int startIndex)
	{
		return indexOfIgnoreCase(src, subS, startIndex, src.length());
	}

	/**
	 * 从给定的位置范围内查找子字符串在源字符串中第一次出现的下标。查找中<b>忽略大小写</b>。
	 * 
	 * @param src
	 *            需要处理的源字符串
	 * @param sub
	 *            需要查找的子字符串
	 * @param startIndex
	 *            开始查找的位置
	 * @param endIndex
	 *            结束位置
	 * @return 查找子串在字符串中第一次出现的下标，找不到返回-1
	 * @see #indexOfIgnoreCase(String, String, int)
	 */
	public static int indexOfIgnoreCase(String src, String sub, int startIndex,
			int endIndex)
	{
		// 判断
		if (startIndex < 0)
		{
			startIndex = 0;
		}

		int srclen = src.length();
		// 判断
		if (endIndex > srclen)
		{
			endIndex = srclen;
		}

		int sublen = sub.length();
		// 判断
		if (sublen == 0)
		{
			return startIndex > srclen ? srclen : startIndex;
		}
		sub = sub.toLowerCase();
		int total = endIndex - sublen + 1;
		char c = sub.charAt(0);
		// 循环
		mainloop: for (int i = startIndex; i < total; i++)
		{
			// 判断
			if (Character.toLowerCase(src.charAt(i)) != c)
			{
				continue;
			}
			int j = 1;
			int k = i + 1;
			// 循环
			while (j < sublen)
			{
				char source = Character.toLowerCase(src.charAt(k));
				// 判断
				if (sub.charAt(j) != source)
				{
					continue mainloop;
				}
				j++;
				k++;
			}
			return i;
		}
		return -1;
	}

	/**
	 * 从字符串末尾索引查找子串第一次出现的下标。查找中<b>忽略大小写</b>。
	 * 
	 * @param s
	 *            源字符串
	 * @param subS
	 *            需要查找的子字符串
	 * 
	 * @return 从字符串末尾查找子串第一次出现的下标，如果没有返回-1
	 * @see #indexOfIgnoreCase(String, String, int)
	 * @see #lastIndexOfIgnoreCase(String, String, int)
	 */
	public static int lastIndexOfIgnoreCase(String s, String subS)
	{
		return lastIndexOfIgnoreCase(s, subS, s.length(), 0);
	}

	/**
	 * 从给定的开始位置开始，从字符串末尾索引查找子串第一次出现的下标。查找中<b>忽略大小写</b>。
	 * 
	 * @param src
	 *            源字符串
	 * @param subS
	 *            需要查找的子字符串
	 * @param startIndex
	 *            开始查找位置的下标
	 * 
	 * @return 从字符串末尾查找子串第一次出现的下标，如果没有返回-1
	 * @see #indexOfIgnoreCase(String, String, int)
	 */
	public static int lastIndexOfIgnoreCase(String src, String subS,
			int startIndex)
	{
		return lastIndexOfIgnoreCase(src, subS, startIndex, 0);
	}

	/**
	 * 从给定的开始位置范围开始，从字符串末尾索引查找子串第一次出现的下标。查找中<b>忽略大小写</b>。
	 * 
	 * @param src
	 *            源字符串
	 * @param sub
	 *            需要查找的子字符串
	 * @param startIndex
	 *            开始查找位置的下标
	 * @param endIndex
	 *            结束查找位置的下标
	 * @return 从字符串末尾查找子串第一次出现的下标，如果没有返回-1
	 */
	public static int lastIndexOfIgnoreCase(String src, String sub,
			int startIndex, int endIndex)
	{
		int sublen = sub.length();
		int srclen = src.length();
		// 判断
		if (sublen == 0)
		{
			return startIndex > srclen ? srclen : (startIndex < -1 ? -1
					: startIndex);
		}
		sub = sub.toLowerCase();
		int total = srclen - sublen;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		char c = sub.charAt(0);
		// 循环
		mainloop: for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (Character.toLowerCase(src.charAt(i)) != c)
			{
				continue;
			}
			int j = 1;
			int k = i + 1;
			// 判断
			while (j < sublen)
			{
				char source = Character.toLowerCase(src.charAt(k));
				// 判断
				if (sub.charAt(j) != source)
				{
					continue mainloop;
				}
				j++;
				k++;
			}
			return i;
		}
		return -1;
	}

	/**
	 * 从给定的开始位置范围[end, start]开始，从字符串末尾索引查找子串第一次出现的下标。查看{@link #indexOf(String, String, int, int)}。
	 * 
	 * @param src
	 *            需要处理的源字符串
	 * @param sub
	 *            需要查找的子串
	 * @param startIndex
	 *            开始查找的位置
	 * @param endIndex
	 *            结束查找的位置
	 * @return 从字符串末尾查找子串第一次出现的下标，如果没有返回-1
	 */
	public static int lastIndexOf(String src, String sub, int startIndex,
			int endIndex)
	{
		int sublen = sub.length();
		int srclen = src.length();
		// 判断
		if (sublen == 0)
		{
			return startIndex > srclen ? srclen : (startIndex < -1 ? -1
					: startIndex);
		}
		int total = srclen - sublen;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		char c = sub.charAt(0);
		// 循环
		mainloop: for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (src.charAt(i) != c)
			{
				continue;
			}
			int j = 1;
			int k = i + 1;
			// 判断
			while (j < sublen)
			{
				// 判断
				if (sub.charAt(j) != src.charAt(k))
				{
					continue mainloop;
				}
				j++;
				k++;
			}
			return i;
		}
		return -1;
	}

	/**
	 * 差找字符在给定字符串中，在范围[end,start]内第一次出现的下标
	 */
	public static int lastIndexOf(String src, char c, int startIndex,
			int endIndex)
	{
		int total = src.length() - 1;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		// 循环
		for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (src.charAt(i) == c)
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 差找字符在给定字符串中，在范围[end,start]内第一次出现的下标。查找中<b>忽略大小写</b>。
	 */
	public static int lastIndexOfIgnoreCase(String src, char c, int startIndex,
			int endIndex)
	{
		int total = src.length() - 1;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		c = Character.toLowerCase(c);
		// 循环
		for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (Character.toLowerCase(src.charAt(i)) == c)
			{
				return i;
			}
		}
		return -1;
	}
	/**
	 * 从字符串结束开始查找第一个空格的下标。
	 */
	public static int lastIndexOfWhitespace(String src)
	{
		return lastIndexOfWhitespace(src, src.length(), 0);
	}

	/**
	 * 从给定位置开始向前查找第一个空格的下标
	 */
	public static int lastIndexOfWhitespace(String src, int startIndex)
	{
		return lastIndexOfWhitespace(src, startIndex, 0);
	}

	/**
	 * 从给定范围[endIndex,startIndex]范围查找第一个空格的下标
	 */
	public static int lastIndexOfWhitespace(String src, int startIndex,
			int endIndex)
	{
		int total = src.length() - 1;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		// 循环
		for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (Character.isWhitespace(src.charAt(i)))
			{
				return i;
			}
		}
		return -1;
	}
	/**
	 * 从字符串末尾开始向前查找第一个非空格字符的下标
	 */
	public static int lastIndexOfNonWhitespace(String src)
	{
		return lastIndexOfNonWhitespace(src, src.length(), 0);
	}
	/**
	 * 从给定位置startIndex开始向前查找第一个非空格字符的下标
	 */
	public static int lastIndexOfNonWhitespace(String src, int startIndex)
	{
		return lastIndexOfNonWhitespace(src, startIndex, 0);
	}
	/**
	 * 从给定位置范围[endIndex,startIndex]开始向前查找第一个非空格字符的下标
	 */
	public static int lastIndexOfNonWhitespace(String src, int startIndex,
			int endIndex)
	{
		int total = src.length() - 1;
		// 判断
		if (total < 0)
		{
			return -1;
		}
		// 判断
		if (startIndex >= total)
		{
			startIndex = total;
		}
		// 判断
		if (endIndex < 0)
		{
			endIndex = 0;
		}
		// 循环
		for (int i = startIndex; i >= endIndex; i--)
		{
			// 判断
			if (Character.isWhitespace(src.charAt(i)) == false)
			{
				return i;
			}
		}
		return -1;
	}

	// ---------------------------------------------------------------- starts
	// and ends

	/**
	 * 判断字符串是否是以给定的子串开始，<b>忽略大小写</b>
	 * 
	 * @param src
	 *            源字符串
	 * @param subS
	 *            子字符串
	 * 
	 * @return 源字符串如果以给定子串开始，返回<code>true</code>，否则返回<code>false</code>
	 */
	public static boolean startsWithIgnoreCase(String src, String subS)
	{
		return startsWithIgnoreCase(src, subS, 0);
	}

	/**
	 * 检查源字符串从给定下标开始是否是以给定子串开始。<b>忽略大小写</b>
	 * 
	 * @param src
	 *            源字符串
	 * @param subS
	 *            子字符串
	 * @param startIndex
	 *            开始检查的位置
	 * 
	 * @return 从给定位置开始源字符串以字符串开始返回<code>true</code>，否则返回<code>false</code>
	 */
	public static boolean startsWithIgnoreCase(String src, String subS,
			int startIndex)
	{
		String sub = subS.toLowerCase();
		int sublen = sub.length();
		// 判断
		if (startIndex + sublen > src.length())
		{
			return false;
		}
		int j = 0;
		int i = startIndex;
		// 判断
		while (j < sublen)
		{
			char source = Character.toLowerCase(src.charAt(i));
			// 判断
			if (sub.charAt(j) != source)
			{
				return false;
			}
			j++;
			i++;
		}
		return true;
	}

	/**
	 * 检查字符串是否以给定的子串结束
	 * 
	 * @param src
	 *            源字符串
	 * @param subS
	 *            子字符串
	 * 
	 * @return 源字符串如果以子字符串结束返回<code>true</code>否则返回<code>false</code>
	 */
	public static boolean endsWithIgnoreCase(String src, String subS)
	{
		String sub = subS.toLowerCase();
		int sublen = sub.length();
		int j = 0;
		int i = src.length() - sublen;
		// 判断
		if (i < 0)
		{
			return false;
		}
		// 循环
		while (j < sublen)
		{
			char source = Character.toLowerCase(src.charAt(i));
			// 判断
			if (sub.charAt(j) != source)
			{
				return false;
			}
			j++;
			i++;
		}
		return true;
	}

	/**
	 * 判断字符串是否以给定字符开始
	 */
	public static boolean startsWithChar(String s, char c)
	{
		// 判断
		if (s.length() == 0)
		{
			return false;
		}
		return s.charAt(0) == c;
	}

	/**
	 * 判断字符串是否以给定字符结束
	 */
	public static boolean endsWithChar(String s, char c)
	{
		// 判断
		if (s.length() == 0)
		{
			return false;
		}
		return s.charAt(s.length() - 1) == c;
	}

	// ---------------------------------------------------------------- count
	// substrings

	/**
	 * 判断子串在源字符串中出现的次数
	 * 
	 * @param source
	 *            源字符串
	 * @param sub
	 *            子字符串
	 * @return 子字符串在源字符串中出现的次数
	 */
	public static int count(String source, String sub)
	{
		return count(source, sub, 0);
	}
	/**
	 * 判断子串从给定位置开始在源字符串中出现的次数
	 * 
	 * @param source
	 *            源字符串
	 * @param sub
	 *            子字符串
	 * @param start
	 *            开始查找的位置下标
	 * @return 子字符串在源字符串中出现的次数
	 */
	public static int count(String source, String sub, int start)
	{
		int count = 0;
		int j = start;
		int sublen = sub.length();
		// 判断
		if (sublen == 0)
		{
			return 0;
		}
		// 判断
		while (true)
		{
			int i = source.indexOf(sub, j);
			// 判断
			if (i == -1)
			{
				break;
			}
			count++;
			j = i + sublen;
		}
		return count;
	}
	/**
	 * 判断某个字符在源字符串中出现的次数
	 * 
	 * @param source
	 *            源字符串
	 * @param c
	 *            需要统计的字符
	 * @return 给定字符在源字符串中出现的次数
	 */
	public static int count(String source, char c)
	{
		return count(source, c, 0);
	}
	/**
	 * 判断某个字符从给定位置开始在源字符串中出现的次数
	 * 
	 * @param source
	 *            源字符串
	 * @param c
	 *            需要统计的字符
	 * @param start
	 *            开始查找的位置下标
	 * @return 给定字符在源字符串中出现的次数
	 */
	public static int count(String source, char c, int start)
	{
		int count = 0;
		int j = start;
		// 判断
		while (true)
		{
			int i = source.indexOf(c, j);
			// 判断
			if (i == -1)
			{
				break;
			}
			count++;
			j = i + 1;
		}
		return count;
	}

	/**
	 * <b>忽略大小写</b>查找子字符串在源字符串出现的次数
	 * 
	 * @param source
	 *            源字符串
	 * @param sub
	 *            需要查找的子字符串
	 * @return 子字符串出现的次数
	 */
	public static int countIgnoreCase(String source, String sub)
	{
		int count = 0;
		int j = 0;
		int sublen = sub.length();
		// 判断
		if (sublen == 0)
		{
			return 0;
		}
		// 判断
		while (true)
		{
			int i = indexOfIgnoreCase(source, sub, j);
			// 判断
			if (i == -1)
			{
				break;
			}
			count++;
			j = i + sublen;
		}
		return count;
	}

	// ---------------------------------------------------------------- string
	// arrays

	/**
	 * 查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            需要查找的字符串数组
	 */
	public static int[] indexOf(String s, String arr[])
	{
		return indexOf(s, arr, 0);
	}

	/**
	 * 从给定下标位置开始查找每一个arr字符串数组中的字符串在源字符串中出现的下标，并返回整数数组，int[0]表示arr数组中第几个字符串在源字符串中出现。
	 * int[1]表示这个字符串在源字符处啊中出现的下标。如果arr数组中所有字符串在源字符串中都没有出现，返回<code>null</code>
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 * @param start
	 *            开始查找位置的下标
	 */
	public static int[] indexOf(String s, String arr[], int start)
	{
		int arrLen = arr.length;
		int index = Integer.MAX_VALUE;
		int last = -1;
		// 判断
		for (int j = 0; j < arrLen; j++)
		{
			int i = s.indexOf(arr[j], start);
			// 判断
			if (i != -1)
			{
				// 判断
				if (i < index)
				{
					index = i;
					last = j;
				}
			}
		}
		return last == -1 ? null : new int[] { last, index };
	}

	/**
	 * 查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 查找过程中<b>忽略大小写</b>
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 */
	public static int[] indexOfIgnoreCase(String s, String arr[])
	{
		return indexOfIgnoreCase(s, arr, 0);
	}

	/**
	 * 查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 查找过程中<b>忽略大小写</b>
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 * @param start
	 *            开始查找位置的下标
	 */
	public static int[] indexOfIgnoreCase(String s, String arr[], int start)
	{
		int arrLen = arr.length;
		int index = Integer.MAX_VALUE;
		int last = -1;
		// 判断
		for (int j = 0; j < arrLen; j++)
		{
			int i = indexOfIgnoreCase(s, arr[j], start);
			// 判断
			if (i != -1)
			{
				// 判断
				if (i < index)
				{
					index = i;
					last = j;
				}
			}
		}
		return last == -1 ? null : new int[] { last, index };
	}

	/**
	 * 从字符串结束位置开始查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 */
	public static int[] lastIndexOf(String s, String arr[])
	{
		return lastIndexOf(s, arr, s.length());
	}

	/**
	 * 从给定位置开始向前查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 * @param fromIndex
	 *            开始查找的下标
	 */
	public static int[] lastIndexOf(String s, String arr[], int fromIndex)
	{
		int arrLen = arr.length;
		int index = -1;
		int last = -1;
		// 判断
		for (int j = 0; j < arrLen; j++)
		{
			int i = s.lastIndexOf(arr[j], fromIndex);
			// 判断
			if (i != -1)
			{
				// 判断
				if (i > index)
				{
					index = i;
					last = j;
				}
			}
		}
		return last == -1 ? null : new int[] { last, index };
	}

	/**
	 * 从字符串结束位置开始查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 * 
	 * @return int[2]
	 */
	public static int[] lastIndexOfIgnoreCase(String s, String arr[])
	{
		return lastIndexOfIgnoreCase(s, arr, s.length());
	}

	/**
	 * 从给定位置开始向前查找给定字符串数组中第一个在源字符串中找到的信息。返回的数组长度为2，第一元素表示在arr数组中，哪一个下标的元素第一次在源字符串中就有出现。
	 * 第二个元素表示，这个字符串再子串中出现的下标。如果给定的字符串数组中所有的字符串都没有在源字符串中出现，那么返回<code>null</code>。
	 * 查找过程中<b>忽略大小写</b>
	 * 
	 * @param s
	 *            源字符串
	 * @param arr
	 *            字符串数组
	 * @param fromIndex
	 *            开始查找位置的下标
	 */
	public static int[] lastIndexOfIgnoreCase(String s, String arr[],
			int fromIndex)
	{
		int arrLen = arr.length;
		int index = -1;
		int last = -1;
		// 判断
		for (int j = 0; j < arrLen; j++)
		{
			int i = lastIndexOfIgnoreCase(s, arr[j], fromIndex);
			// 判断
			if (i != -1)
			{
				// 判断
				if (i > index)
				{
					index = i;
					last = j;
				}
			}
		}
		return last == -1 ? null : new int[] { last, index };
	}

	/**
	 * 比较两个字符串数组是否相等
	 * 
	 * @param as
	 *            第一个字符串数组
	 * @param as1
	 *            第二个字符串数组
	 * 
	 * @return 如果数组中对应元素相等返回<code>true</code>
	 */
	public static boolean equals(String as[], String as1[])
	{
		//// 判断
		if (as.length != as1.length)
		{
			return false;
		}
		// 判断
		for (int i = 0; i < as.length; i++)
		{
			// 判断
			if (as[i].equals(as1[i]) == false)
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 比较两个字符串数组是否相等。比较过程中<b>忽略大小写</b>
	 * 
	 * @param as
	 *            第一个字符串数组
	 * @param as1
	 *            第二个字符串数组
	 * 
	 * @return 如果数组中对应元素相等返回<code>true</code>
	 */
	public static boolean equalsIgnoreCase(String as[], String as1[])
	{
		// 判断
		if (as.length != as1.length)
		{
			return false;
		}
		// 判断
		for (int i = 0; i < as.length; i++)
		{
			// 判断
			if (as[i].equalsIgnoreCase(as1[i]) == false)
			{
				return false;
			}
		}
		return true;
	}

	/**
	 * 将源字符串中的批量子字符串sub，用with中的字符串替换
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            子字符串数组
	 * @param with
	 *            替换字符串数组
	 * 
	 * @return 将源字符串中的子字符串数组用替换字符串数组中的元素替换
	 */
	public static String replace(String s, String[] sub, String[] with)
	{
		// 判断
		if ((sub.length != with.length) || (sub.length == 0))
		{
			return s;
		}
		int start = 0;
		StringBuilder buf = new StringBuilder(s.length());
		// 判断
		while (true)
		{
			int[] res = indexOf(s, sub, start);
			// 判断循环
			if (res == null)
			{
				break;
			}
			int end = res[1];
			buf.append(s.substring(start, end));
			buf.append(with[res[0]]);
			start = end + sub[res[0]].length();
		}
		buf.append(s.substring(start));
		return buf.toString();
	}

	/**
	 * 将源字符串中的批量子字符串sub，用with中的字符串替换。<b>替换比较中忽略大小写</b>
	 * 
	 * @param s
	 *            源字符串
	 * @param sub
	 *            子字符串数组
	 * @param with
	 *            替换字符串数组
	 * 
	 * @return 将源字符串中的子字符串数组用替换字符串数组中的元素替换
	 */
	public static String replaceIgnoreCase(String s, String[] sub, String[] with)
	{
		// 判断循环
		if ((sub.length != with.length) || (sub.length == 0))
		{
			return s;
		}
		int start = 0;
		StringBuilder buf = new StringBuilder(s.length());
		// 判断循环
		while (true)
		{
			int[] res = indexOfIgnoreCase(s, sub, start);
			// 判断循环
			if (res == null)
			{
				break;
			}
			int end = res[1];
			buf.append(s.substring(start, end));
			buf.append(with[res[0]]);
			start = end + sub[0].length();
		}
		buf.append(s.substring(start));
		return buf.toString();
	}

	// ---------------------------------------------------------------- the one

	/**
	 * 比较源字符串和给定的字符串数组，如果给定字符串数组中有任何一个字符串在源字符串中出现，就返回这个字符串在dest中的下标。都没有返回<code>-1</code>
	 */
	public static int equalsOne(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{
			// 判断循环
			if (src.equals(dest[i]))
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 比较源字符串和给定的字符串数组，如果给定字符串数组中有任何一个字符串在源字符串中出现，就返回这个字符串在dest中的下标。都没有返回<code>-1</code>。
	 * <b>比较过程中忽略大小写</b>
	 */
	public static int equalsOneIgnoreCase(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{
			// 判断循环
			if (src.equalsIgnoreCase(dest[i]))
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 检查给定字符串数组中是否有字符串是源字符串的开始部分，如果有返回这个字符串在dest中的下标，否则返回<code>-1</code>
	 */
	public static int startsWithOne(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{

			String m = dest[i];
			// 判断循环
			if (m == null)
			{
				continue;
			}
			// 判断循环
			if (src.startsWith(m))
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 检查给定字符串数组中是否有字符串是源字符串的开始部分，如果有返回这个字符串在dest中的下标，否则返回<code>-1</code>。
	 * <b>比较过程中忽略大小写</b>
	 */
	public static int startsWithOneIgnoreCase(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{
			String m = dest[i];
			// 判断循环
			if (m == null)
			{
				continue;
			}
			// 判断循环
			if (startsWithIgnoreCase(src, m))
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 判断给定字符串数组中是否有字符串是源字符串的结束部分，如果有返回这个字符串在dest中的下标，否则返回<code>-1</code>
	 */
	public static int endsWithOne(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{
			String m = dest[i];
			// 判断循环
			if (m == null)
			{
				continue;
			}
			// 判断循环
			if (src.endsWith(m))
			{
				return i;
			}
		}
		return -1;
	}

	/**
	 * 判断给定字符串数组中是否有字符串是源字符串的结束部分，如果有返回这个字符串在dest中的下标，否则返回<code>-1</code>。
	 * <b>比较过程中忽略大小写</b>
	 */
	public static int endsWithOneIgnoreCase(String src, String[] dest)
	{
		// 判断循环
		for (int i = 0; i < dest.length; i++)
		{
			String m = dest[i];
			// 判断循环
			if (m == null)
			{
				continue;
			}
			// 判断循环
			if (endsWithIgnoreCase(src, m))
			{
				return i;
			}
		}
		return -1;
	}

	// ---------------------------------------------------------------- char
	// based

	/**
	 * @see #indexOfChars(String, String, int)
	 */
	public static int indexOfChars(String string, String chars)
	{
		return indexOfChars(string, chars, 0);
	}

	/**
	 * 从给定位置开始查找给定的字符序列（chars字符串）中，哪个字符在字符串中存在，并返回这个字符在源字符串中的下标。如果都没有返回<code>-1</code>
	 */
	public static int indexOfChars(String string, String chars, int startindex)
	{
		int stringLen = string.length();
		int charsLen = chars.length();
		// 判断循环
		if (startindex < 0)
		{
			startindex = 0;
		}
		// 判断循环
		for (int i = startindex; i < stringLen; i++)
		{
			char c = string.charAt(i);
			// 判断循环
			for (int j = 0; j < charsLen; j++)
			{
				// 判断循环
				if (c == chars.charAt(j))
				{
					return i;
				}
			}
		}
		return -1;
	}
	/**
	 * 查找给定的字符序列（chars数组）中，哪个字符在字符串中存在，并返回这个字符在源字符串中的下标。如果都没有返回<code>-1</code>
	 */
	public static int indexOfChars(String string, char[] chars)
	{
		return indexOfChars(string, chars, 0);
	}

	/**
	 * 从给定位置开始查找给定的字符序列（chars数组）中，哪个字符在字符串中存在，并返回这个字符在源字符串中的下标。如果都没有返回<code>-1</code>
	 */
	public static int indexOfChars(String string, char[] chars, int startindex)
	{
		int stringLen = string.length();
		int charsLen = chars.length;
		// 判断循环
		for (int i = startindex; i < stringLen; i++)
		{
			char c = string.charAt(i);
			// 判断循环
			for (int j = 0; j < charsLen; j++)
			{
				// 判断循环
				if (c == chars[j])
				{
					return i;
				}
			}
		}
		return -1;
	}

	/**
	 * 返回字符串中第一个空格的下标
	 */
	public static int indexOfWhitespace(String string)
	{
		return indexOfWhitespace(string, 0, string.length());
	}
	/**
	 * 从给定位置开始查找并返回字符串中第一个空格的下标
	 */
	public static int indexOfWhitespace(String string, int startindex)
	{
		return indexOfWhitespace(string, startindex, string.length());
	}

	/**
	 * 从给定位置范围[startIndex,endIndex)开始查找并返回字符串中第一个空格的下标
	 */
	public static int indexOfWhitespace(String string, int startindex,
			int endindex)
	{
		// 判断循环
		for (int i = startindex; i < endindex; i++)
		{
			// 判断循环
			if (CharUtil.isWhitespace(string.charAt(i)))
			{
				return i;
			}
		}
		return -1;
	}
	/**
	 * 返回字符串中第一个非空格的下标
	 */
	public static int indexOfNonWhitespace(String string)
	{
		return indexOfNonWhitespace(string, 0, string.length());
	}
	/**
	 * 从给定位置开始查找并返回字符串中第一个非空格的下标
	 */
	public static int indexOfNonWhitespace(String string, int startindex)
	{
		return indexOfNonWhitespace(string, startindex, string.length());
	}
	/**
	 * 从给定位置范围[startIndex,endIndex)开始查找并返回字符串中第一个非空格的下标
	 */
	public static int indexOfNonWhitespace(String string, int startindex,
			int endindex)
	{
		// 判断循环
		for (int i = startindex; i < endindex; i++)
		{
			// 判断循环
			if (CharUtil.isWhitespace(string.charAt(i)) == false)
			{
				return i;
			}
		}
		return -1;
	}

	// ---------------------------------------------------------------- strip,
	// trim

	/**
	 * 去除字符串开始的给定字符
	 */
	public static String stripLeadingChar(String string, char c)
	{
		// 判断循环
		if (string.length() > 0)
		{
			// 判断循环
			if (string.charAt(0) == c)
			{
				return string.substring(1);
			}
		}
		return string;
	}

	/**
	 * 如果字符串以给定字符结束，那么除去这个字符并返回
	 */
	public static String stripTrailingChar(String string, char c)
	{
		// 判断循环
		if (string.length() > 0)
		{
			// 判断循环
			if (string.charAt(string.length() - 1) == c)
			{
				return string.substring(0, string.length() - 1);
			}
		}
		return string;
	}

	/**
	 * 去除字符串数组中所有字符串的首尾空格。参数字符串数组不允许为<code>null</code>
	 */
	public static void trimAll(String[] strings)
	{
		// 判断循环
		for (int i = 0; i < strings.length; i++)
		{
			String string = strings[i];
			// 判断循环
			if (string != null)
			{
				strings[i] = string.trim();
			}
		}
	}

	/**
	 * 去除字符串数组中所有字符串首尾空格。并且如果去掉空格后字符串为空串，就转换成<code>null</code>
	 * 
	 * @see #trimDown(String)
	 */
	public static void trimDownAll(String[] strings)
	{
		// 判断循环
		for (int i = 0; i < strings.length; i++)
		{
			String string = strings[i];
			// 判断循环
			if (string != null)
			{
				strings[i] = trimDown(string);
			}
		}
	}

	/**
	 * 去除字符串首尾空格，并且如果去除空格后字符串为空串，那么返回<code>null</code>
	 */
	public static String trimDown(String string)
	{
		string = string.trim();
		// 判断循环
		if (string.length() == 0)
		{
			string = null;
		}
		return string;
	}

	/**
	 * 修剪空字符串，转换为<code>null</code>
	 */
	public static String crop(String string)
	{
		// 判断循环
		if (string.length() == 0)
		{
			return null;
		}
		return string;
	}

	/**
	 * 修剪整个字符串数组。将所有空串转换为<code>null</code>
	 */
	public static void cropAll(String[] strings)
	{
		// 判断循环
		for (int i = 0; i < strings.length; i++)
		{
			String string = strings[i];
			// 判断循环
			if (string != null)
			{
				string = crop(strings[i]);
			}
			strings[i] = string;
		}
	}

	/**
	 * 除去字符串左侧的所有空格（字符串开始的所有空格）
	 */
	public static String trimLeft(String src)
	{
		int len = src.length();
		int st = 0;
		// 判断循环
		while ((st < len) && (CharUtil.isWhitespace(src.charAt(st))))
		{
			st++;
		}
		return st > 0 ? src.substring(st) : src;
	}

	/**
	 * 除去字符串右侧的所有字符（字符串结束的所有空格）
	 */
	public static String trimRight(String src)
	{
		int len = src.length();
		int count = len;
		// 判断循环
		while ((len > 0) && (CharUtil.isWhitespace(src.charAt(len - 1))))
		{
			len--;
		}
		return (len < count) ? src.substring(0, len) : src;
	}

	// ---------------------------------------------------------------- regions

	/**
	 * @see #indexOfRegion(String, String, String, int)
	 */
	public static int[] indexOfRegion(String string, String leftBoundary,
			String rightBoundary)
	{
		return indexOfRegion(string, leftBoundary, rightBoundary, 0);
	}

	/**
	 * Returns indexes of the first region without escaping character.
	 * 
	 * @see #indexOfRegion(String, String, String, char, int)
	 */
	public static int[] indexOfRegion(String string, String leftBoundary,
			String rightBoundary, int offset)
	{
		int ndx = offset;
		int[] res = new int[4];
		ndx = string.indexOf(leftBoundary, ndx);
		// 判断循环
		if (ndx == -1)
		{
			return null;
		}
		res[0] = ndx;
		ndx += leftBoundary.length();
		res[1] = ndx;

		ndx = string.indexOf(rightBoundary, ndx);
		// 判断循环
		if (ndx == -1)
		{
			return null;
		}
		res[2] = ndx;
		res[3] = ndx + rightBoundary.length();
		return res;
	}

	/**
	 * @see #indexOfRegion(String, String, String, char, int)
	 */
	public static int[] indexOfRegion(String string, String leftBoundary,
			String rightBoundary, char escape)
	{
		return indexOfRegion(string, leftBoundary, rightBoundary, escape, 0);
	}

	/**
	 * Returns indexes of the first string region. Region is defined by its left
	 * and right boundary. Return value is an array of the following indexes:
	 * <ul>
	 * <li>start of left boundary index</li>
	 * <li>region start index, i.e. end of left boundary</li>
	 * <li>region end index, i.e. start of right boundary</li>
	 * <li>end of right boundary index</li>
	 * </ul>
	 * <p>
	 * Escape character may be used to prefix boundaries so they can be ignored.
	 * Double escaped region will be found, and first index of the result will
	 * be decreased to include one escape character. If region is not founded,
	 * <code>null</code> is returned.
	 */
	public static int[] indexOfRegion(String string, String leftBoundary,
			String rightBoundary, char escape, int offset)
	{
		int ndx = offset;
		int[] res = new int[4];
		// 判断循环
		while (true)
		{
			ndx = string.indexOf(leftBoundary, ndx);
			// 判断循环
			if (ndx == -1)
			{
				return null;
			}
			int leftBoundaryLen = leftBoundary.length();
			// 判断循环
			if (ndx > 0)
			{
				// 判断循环
				if (string.charAt(ndx - 1) == escape)
				{
					// check previous char
					boolean cont = true;
					// 判断循环
					if (ndx > 1)
					{
						// 判断循环
						if (string.charAt(ndx - 2) == escape)
						{
							// check double escapes
							ndx--;
							leftBoundaryLen++;
							cont = false;
						}
					}
					// 判断循环
					if (cont)
					{
						ndx += leftBoundaryLen;
						continue;
					}
				}
			}
			res[0] = ndx;
			ndx += leftBoundaryLen;
			res[1] = ndx;
			// 判断循环
			while (true)
			{
				// find right boundary
				ndx = string.indexOf(rightBoundary, ndx);
				// 判断循环
				if (ndx == -1)
				{
					return null;
				}
				// 判断循环
				if (ndx > 0)
				{
					// 判断循环
					if (string.charAt(ndx - 1) == escape)
					{
						ndx += rightBoundary.length();
						continue;
					}
				}
				res[2] = ndx;
				res[3] = ndx + rightBoundary.length();
				return res;
			}
		}
	}

	// ---------------------------------------------------------------- charset

	/**
	 * 转换字符串的字符集。
	 * 
	 * @param source，源字符串
	 * @param srcCharsetName，源字符集名字
	 * @param newCharsetName，新字符集名字
	 * @return 将源字符集下的字符串转换到新字符集
	 */
	public static String convertCharset(String source, String srcCharsetName,
			String newCharsetName) throws UnsupportedEncodingException
	{
		return new String(source.getBytes(srcCharsetName), newCharsetName);
	}

	/**
	 * 按照Java规则，将字符串中的转义字符转换成Java中的方式。（斜杠转换为双斜杠）
	 */
	public static String escapeJava(String string)
	{
		int strLen = string.length();
		StringBuilder sb = new StringBuilder(strLen);
		// 判断循环
		for (int i = 0; i < strLen; i++)
		{
			char c = string.charAt(i);
			// 判断循环
			switch (c)
			{
			case '\b':
				sb.append("\\b");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\r':
				sb.append("\\r");
				break;
			case '\"':
				sb.append("\\\"");
				break;
			case '\\':
				sb.append("\\\\");
				break;
			default:
				// 判断循环
				if ((c < 32) || (c > 127))
				{
					String hex = Integer.toHexString(c);
					sb.append("\\u");
					// 判断循环
					for (int k = hex.length(); k < 4; k++)
					{
						sb.append('0');
					}
					sb.append(hex);
				} 
				else
				{
					sb.append(c);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 按照Java规则，将转义字符转换为非方式。（双斜杠转换成斜杠）
	 */
	public static String unescapeJava(String str)
	{
		char[] chars = str.toCharArray();

		StringBuilder sb = new StringBuilder(str.length());
		// 判断循环
		for (int i = 0; i < chars.length; i++)
		{
			char c = chars[i];
			// 判断循环
			if (c != '\\')
			{
				sb.append(c);
				continue;
			}
			i++;
			c = chars[i];
			// 判断循环
			switch (c)
			{
			case 'b':
				sb.append('\b');
				break;
			case 't':
				sb.append('\t');
				break;
			case 'n':
				sb.append('\n');
				break;
			case 'f':
				sb.append('\f');
				break;
			case 'r':
				sb.append('\r');
				break;
			case '"':
				sb.append('\"');
				break;
			case '\\':
				sb.append('\\');
				break;
			case 'u':
				char hex = (char) Integer.parseInt(new String(chars, i + 1, 4),
						16);
				sb.append(hex);
				i += 4;
				break;
			default:
				throw new IllegalArgumentException(
						"Invalid escaping character: " + c);
			}
		}
		return sb.toString();
	}

	// ---------------------------------------------------------------- chars

	/**
	 * 判断字符串中给定位置的字符是否与给定的字符相同。
	 * 
	 * @param String str，源字符串
	 * @param int index，给定下标位置
	 * @param char charToCompare，比较字符
	 * @return 如果源字符串在给定位置上的字符与比较字符相同，返回<code>true</code>
	 */
	public static boolean isCharAtEqual(String string, int index,
			char charToCompare)
	{
		// 判断循环
		if ((index < 0) || (index >= string.length()))
		{
			return false;
		}
		return string.charAt(index) == charToCompare;
	}

	// ---------------------------------------------------------------- surround

	/**
	 * @see #surround(String, String, String)
	 */
	public static String surround(String string, String fix)
	{
		return surround(string, fix, fix);
	}

	/**
	 * 如果字符串以给定的前缀开始且以给定的后缀结束，就返回源字符串，否则，将源字符串加上对应的前缀或者后缀。
	 * 
	 * @param String str，源字符串
	 * @param String prefix，前缀字符串
	 * @param String suffix，后缀字符串
	 * @return String 返回加入前缀和后缀的字符串，如果源字符串拥有同样的前缀和后缀就不做任何处理
	 */
	public static String surround(String string, String prefix, String suffix)
	{
		// 判断循环
		if (string.startsWith(prefix) == false)
		{
			string = prefix + string;
		}
		// 判断循环
		if (string.endsWith(suffix) == false)
		{
			string += suffix;
		}
		return string;
	}

	/**
	 * 为字符串添加前缀，如果已经具有相同的前缀就不做任何处理
	 */
	public static String prefix(String string, String prefix)
	{
		// 判断循环
		if (string.startsWith(prefix) == false)
		{
			string = prefix + string;
		}
		return string;
	}

	/**
	 * 为字符串追加后缀，如果字符串已经拥有相同的后缀就不做任何处理
	 */
	public static String suffix(String string, String suffix)
	{
		// 判断循环
		if (string.endsWith(suffix) == false)
		{
			string += suffix;
		}
		return string;
	}

	// ---------------------------------------------------------------- cut

	/**
	 * 剪切字符串从开始到子串开始的下标位置。
	 * 
	 * @param String string，源字符串
	 * @param String substring，子字符串
	 * @return String 从源字符串截取从开始到子串下标的字符串
	 */
	public static String cutToIndexOf(String string, String substring)
	{
		int i = string.indexOf(substring);
		// 判断循环
		if (i != -1)
		{
			string = string.substring(0, i);
		}
		return string;
	}

	/**
	 * 剪切源字符串，从开始位置到给定字符的下标。如果不含有给定字符，那么返回整个源字符串
	 */
	public static String cutToIndexOf(String string, char c)
	{
		int i = string.indexOf(c);
		// 判断循环
		if (i != -1)
		{
			string = string.substring(0, i);
		}
		return string;
	}

	/**
	 * 剪切从子串下标位置开始到字符串结束的字符串。如果源字符串不含有给定的子字符串，那么返回整个源字符串
	 */
	public static String cutFromIndexOf(String string, String substring)
	{
		int i = string.indexOf(substring);
		// 判断循环
		if (i != -1)
		{
			string = string.substring(i);
		}
		return string;
	}

	/**
	 * 剪切从给定字符所在下标位置到字符串结束的字符串。如果给定的字符在源字符串中不存在，那么返回整个源字符串
	 */
	public static String cutFromIndexOf(String string, char c)
	{
		int i = string.indexOf(c);
		// 判断循环
		if (i != -1)
		{
			string = string.substring(i);
		}
		return string;
	}

	/**
	 * 如果字符串存在给定的前缀字符串，那么除去这个前缀字符串
	 */
	public static String cutPrefix(String string, String prefix)
	{
		// 判断循环
		if (string.startsWith(prefix))
		{
			string = string.substring(prefix.length());
		}
		return string;
	}

	/**
	 * 如果字符串含有给定的后缀字符串，那么去除这个后缀字符串
	 */
	public static String cutSuffix(String string, String suffix)
	{
		// 判断循环
		if (string.endsWith(suffix))
		{
			string = string.substring(0, string.length() - suffix.length());
		}
		return string;
	}

	/**
	 * @see #cutSurrounding(String, String, String)
	 */
	public static String cutSurrounding(String string, String fix)
	{
		return cutSurrounding(string, fix, fix);
	}

	/**
	 * 删除字符串环绕的前缀和后缀
	 */
	public static String cutSurrounding(String string, String prefix,
			String suffix)
	{
		int start = 0;
		int end = string.length();
		// 判断循环
		if (string.startsWith(prefix))
		{
			start = prefix.length();
		}
		// 判断循环
		if (string.endsWith(suffix))
		{
			end -= suffix.length();
		}

		return string.substring(start, end);
	}

	// ---------------------------------------------------------------- escaped

	/**
	 * 判断当前位置的字符是否是是转义字符，也就是该字符前是否有转义字符斜杠
	 */
	public static boolean isCharAtEscaped(String src, int ndx, char escapeChar)
	{
		// 判断循环
		if (ndx == 0)
		{
			return false;
		}
		ndx--;
		return src.charAt(ndx) == escapeChar;
	}

	/**
	 * 
	 * 方法名称: indexOfUnescapedChar 内容摘要: TODO(这里详细描述这个方法的作用)
	 * 
	 * @param src
	 * @param sub
	 * @param escapeChar
	 * @return
	 *
	 * @author: Baisong
	 * @time:2020年8月25日 下午1:07:45
	 */
	public static int indexOfUnescapedChar(String src, char sub, char escapeChar)
	{
		return indexOfUnescapedChar(src, sub, escapeChar, 0);
	}

	/**
	 * 
	 * 方法名称: indexOfUnescapedChar 内容摘要: TODO(这里详细描述这个方法的作用)
	 * 
	 * @param src
	 * @param sub
	 * @param escapeChar
	 * @param startIndex
	 * @return
	 *
	 * @author: Baisong
	 * @time:2020年8月25日 下午1:07:51
	 */
	public static int indexOfUnescapedChar(String src, char sub,
			char escapeChar, int startIndex)
	{
		// 判断循环
		if (startIndex < 0)
		{
			startIndex = 0;
		}
		int srclen = src.length();
		char previous;
		char c = 0;
		// 判断循环
		for (int i = startIndex; i < srclen; i++)
		{
			previous = c;
			c = src.charAt(i);
			// 判断循环
			if (c == sub)
			{
				// 判断循环
				if (i > startIndex)
				{
					// 判断循环
					if (previous == escapeChar)
					{
						continue;
					}
				}
				return i;
			}
		}
		return -1;

	}

	// ---------------------------------------------------------------- insert
	/**
	 * 在字符串开始插入对应的字符串。
	 * 
	 * @param String src，源字符串
	 * @param String insert，插入的字符串
	 * @return 返回在字符串开始插入好的字符串
	 */
	public static String insert(String src, String insert)
	{
		return insert(src, insert, 0);
	}

	/**
	 * 在给定位置插入对应的字符串。
	 * 
	 * @param String src，源字符串
	 * @param String insert，插入的字符串
	 * @param int offset，在给定位置插入
	 * @return 返回在给定位置插入好的字符串
	 */
	public static String insert(String src, String insert, int offset)
	{
		// 判断循环
		if (offset < 0)
		{
			offset = 0;
		}
		// 判断循环
		if (offset > src.length())
		{
			offset = src.length();
		}
		StringBuilder sb = new StringBuilder(src);
		sb.insert(offset, insert);
		return sb.toString();
	}

	// ---------------------------------------------------------------- misc

	/**
	 * 创建一个按指定次数重复字符的字符串
	 */
	public static String repeat(char c, int count)
	{
		char[] result = new char[count];
		// 判断循环
		for (int i = 0; i < count; i++)
		{
			result[i] = c;
		}
		return new String(result);
	}

	/**
	 * 字符串反转
	 */
	public static String reverse(String s)
	{
		StringBuilder result = new StringBuilder(s.length());
		// 判断循环
		for (int i = s.length() - 1; i >= 0; i--)
		{
			result.append(s.charAt(i));
		}
		return result.toString();
	}

	/**
	 * 返回两个字符串最大相同的前缀字符串，如果没有相同的前缀返回空串
	 */
	public static String maxCommonPrefix(String one, String two)
	{
		final int minLength = Math.min(one.length(), two.length());

		final StringBuilder sb = new StringBuilder(minLength);
		// 判断循环
		for (int pos = 0; pos < minLength; pos++)
		{
			final char currentChar = one.charAt(pos);
			// 判断循环
			if (currentChar != two.charAt(pos))
			{
				break;
			}
			sb.append(currentChar);
		}

		return sb.toString();
	}

	// ---------------------------------------------------------------- camel
	// case

	/**
	 * 转换CamelCase方式的字符串到小写字符串，并按照给定的分隔符进行分割。转换按如下规则进行：
	 * <ul>
	 * <li>
	 * 将CamelCase字符串中每一个大写字母转换成两个字符，一个分割符加上小写字母。有三种特例
	 * <ol>
	 * <li>对于连续的大写字母，只转换其中第一个大写字母为分隔符加上小写字母，其他大写字母只转换为小写字母，例如<code>theFOO</code>转换为<code>the_foo</code>
	 * <li>如果大写字母是字符串的开始，那么不加入分隔符，只转换为小写字母，例如<code>Foo</code>转换为<code>foo</code>而不是<code>_foo</code>
	 * <li>在CamelCase中，大写字母前面已经有分隔符了，那么不再加入分隔符，例如<code>user_Name</code>转换为<code>user_name</code>而不是<code>user__name</code>
	 * </ol>
	 * <li>
	 * 如果在CamelCase字符串中已经以分隔符开始，那么转换后的字符串中不包含开始的分隔符。除非整个CamelCase字符串本身就是一个分隔符。
	 * 
	 */
	public static String fromCamelCase(String input, char separator)
	{
		int length = input.length();
		StringBuilder result = new StringBuilder(length * 2);
		int resultLength = 0;
		boolean prevTranslated = false;
		// 判断循环
		for (int i = 0; i < length; i++)
		{
			char c = input.charAt(i);
			// 判断循环
			if (i > 0 || c != separator)
			{
				// skip first starting separator
				if (Character.isUpperCase(c))
				{
					// 判断循环
					if (!prevTranslated && resultLength > 0
							&& result.charAt(resultLength - 1) != separator)
					{
						result.append(separator);
						resultLength++;
					}
					c = Character.toLowerCase(c);
					prevTranslated = true;
				}
				else
				{
					prevTranslated = false;
				}
				result.append(c);
				resultLength++;
			}
		}
		return resultLength > 0 ? result.toString() : input;
	}

	/**
	 * 将分割符分割的字符串转换为CamelCase字符串
	 */
	public static String toCamelCase(String input, boolean firstCharUppercase,
			char separator)
	{
		int length = input.length();
		StringBuilder sb = new StringBuilder(length);
		boolean upperCase = firstCharUppercase;
		// 判断循环
		for (int i = 0; i < length; i++)
		{
			char ch = input.charAt(i);
			// 判断循环
			if (ch == separator)
			{
				upperCase = true;
			} 
			else if (upperCase)
			{
				sb.append(Character.toUpperCase(ch));
				upperCase = false;
			} 
			else
			{
				sb.append(ch);
			}
		}
		return sb.toString();
	}

	// ---------------------------------------------------------------- prefixes

	/**
	 * 查找多个字符串拥有的一般前缀字符串。如果找不到就返回空串
	 */
	public static String findCommonPrefix(String... strings)
	{
		StringBuilder prefix = new StringBuilder();
		int index = 0;
		char c = 0;
		// 判断循环
		loop: while (true)
		{
			// 判断循环
			for (int i = 0; i < strings.length; i++)
			{

				String s = strings[i];
				// 判断循环
				if (index == s.length())
				{
					break loop;
				}
				// 判断循环
				if (i == 0)
				{
					c = s.charAt(index);
				} 
				else
				{
					// 判断循环
					if (s.charAt(index) != c)
					{
						break loop;
					}
				}
			}

			index++;
			prefix.append(c);
		}
		return prefix.length() == 0 ? "" : prefix.toString();
	}

	// ---------------------------------------------------------------- shorten

	/**
	 * 将源字符串缩短到给定长度。截断其他部分的字符串。如果给定suffix，那么在截断源字符串后加入后缀字符串，并满足长度要求。
	 */
	public static String shorten(String s, int length, String suffix)
	{
		length -= suffix.length();
		// 判断循环
		if (s.length() > length)
		{
			// 判断循环
			for (int j = length; j >= 0; j--)
			{
				// 判断循环
				if (CharUtil.isWhitespace(s.charAt(j)))
				{
					length = j;
					break;
				}
			}
			String temp = s.substring(0, length);
			s = temp.concat(suffix);
		}

		return s;
	}

}
